package cs342.project1.mathNotebook.gui;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

import javax.swing.JFileChooser;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.JLabel;

import cs342.project1.mathNotebook.PKI.SimpleRSAKeyPair;
import cs342.project1.mathNotebook.db.DBPerson;
import cs342.project1.mathNotebook.db.DatabaseContext;
import cs342.project1.mathNotebook.db.DatabaseException;
import cs342.project1.mathNotebook.db.DatabaseUnconnectableException;


/**
 *
 * @author aaron
 */
public class NewUserWizard extends javax.swing.JDialog {
	
	//Use a state machine to make enabling buttons and panels easier
	private enum State {
		WELCOME,
		USERNAME,
		PROFILE,
		KEY,
		COMPLETE,
		ERROR		
	}
	private State state;
	private DatabaseContext context = null;
	public DatabaseContext getContext() {
		return this.context;
	}
	
    /** A return status code - returned if Cancel button has been pressed */
    public static final int RET_CANCEL = 0;
    /** A return status code - returned if OK button has been pressed */
    public static final int RET_OK = 1;

    /** Creates new form */
    public NewUserWizard(java.awt.Frame parent, boolean modal, DatabaseContext context) {
        super(parent, modal);
        this.context = context;
        initComponents();
        
        //check that supplied context works
        boolean works = (context != null);
        if(works) {
	        try {
	        	context.getConnection();
	        } catch (DatabaseUnconnectableException e) {
	        	works = false;
	        }
        }
        
        if(works) {
        	//start in the welcome screen state
        	this.setWelcomeState();
        } else {
        	//if it doesn't work, start in the error state--user can cancel only.
        	this.setErrorState();
        }
    }

    /** @return the return status of this dialog - one of RET_OK or RET_CANCEL */
    public int getReturnStatus() {
        return returnStatus;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        buttonPanel = new javax.swing.JPanel();
        cancelButton = new javax.swing.JButton();
        backButton = new javax.swing.JButton();
        nextButton = new javax.swing.JButton();
        finishButton = new javax.swing.JButton();
        progressBar = new javax.swing.JProgressBar();
        jLayeredPane1 = new javax.swing.JLayeredPane();
        welcomePanel = new javax.swing.JPanel();
        WelcomeLabel = new javax.swing.JLabel();
        usernamePanel = new javax.swing.JPanel();
        instructionLabel = new javax.swing.JLabel();
        usernameField = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        usernameErrorLabel = new javax.swing.JLabel();
        profilePanel = new javax.swing.JPanel();
        instructionLabel1 = new javax.swing.JLabel();
        realnameField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        realnameErrorLabel = new javax.swing.JLabel();
        emailAddressErrorLabel = new javax.swing.JLabel();
        emailAddressField = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        keyPanel = new javax.swing.JPanel();
        instructionLabel2 = new javax.swing.JLabel();
        filenameField = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        browseButton = new javax.swing.JButton();
        errorPanel = new javax.swing.JPanel();
        instructionLabel4 = new javax.swing.JLabel();
        finishPanel = new javax.swing.JPanel();
        instructionLabel3 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setName("Form"); // NOI18N
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                closeDialog(evt);
            }
        });

        buttonPanel.setName("buttonPanel"); // NOI18N

        cancelButton.setText("Cancel");
        cancelButton.setName("cancelButton"); // NOI18N
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });

        backButton.setText("Back");
        backButton.setName("backButton"); // NOI18N
        backButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                backButtonActionPerformed(evt);
            }
        });

        nextButton.setText("Next");
        nextButton.setName("nextButton"); // NOI18N
        nextButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nextButtonActionPerformed(evt);
            }
        });

        finishButton.setText("Finish");
        finishButton.setName("finishButton"); // NOI18N
        finishButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                finishButtonActionPerformed(evt);
            }
        });

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout buttonPanelLayout = new javax.swing.GroupLayout(buttonPanel);
        buttonPanel.setLayout(buttonPanelLayout);
        buttonPanelLayout.setHorizontalGroup(
            buttonPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(buttonPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(cancelButton)
                .addGap(18, 18, 18)
                .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 153, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addComponent(backButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(nextButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(finishButton)
                .addContainerGap())
        );
        buttonPanelLayout.setVerticalGroup(
            buttonPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, buttonPanelLayout.createSequentialGroup()
                .addContainerGap(17, Short.MAX_VALUE)
                .addGroup(buttonPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(buttonPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(cancelButton)
                        .addComponent(nextButton)
                        .addComponent(backButton)
                        .addComponent(finishButton)))
                .addContainerGap())
        );

        jLayeredPane1.setName("jLayeredPane1"); // NOI18N

        welcomePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Welcome"));
        welcomePanel.setName("welcomePanel"); // NOI18N

        WelcomeLabel.setText("<html>Welcome to the New User Wizard.  This wizard will walk you through the process of creating a new user profile for accessing the math in the cloud database.  To get started, click next.</html>");
        WelcomeLabel.setName("WelcomeLabel"); // NOI18N

        javax.swing.GroupLayout welcomePanelLayout = new javax.swing.GroupLayout(welcomePanel);
        welcomePanel.setLayout(welcomePanelLayout);
        welcomePanelLayout.setHorizontalGroup(
            welcomePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(welcomePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(WelcomeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)
                .addContainerGap())
        );
        welcomePanelLayout.setVerticalGroup(
            welcomePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(welcomePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(WelcomeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 248, Short.MAX_VALUE)
                .addContainerGap())
        );

        welcomePanel.setBounds(10, 10, 530, 316);
        jLayeredPane1.add(welcomePanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        usernamePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Choose a username"));
        usernamePanel.setName("usernamePanel"); // NOI18N

        instructionLabel.setText("<html>First you'll need to select a unique username which you will use to access the cloud database.<br/><br/>Enter a name in the box below.  Once your choice is accepted, click next.</html>");
        instructionLabel.setName("instructionLabel"); // NOI18N

        usernameField.setName("usernameField"); // NOI18N
        usernameField.getDocument().addDocumentListener(new DocumentListener() {
			
			@Override
			public void removeUpdate(DocumentEvent e) {
				usernameFieldActionPerformed(e);								
			}
			
			@Override
			public void insertUpdate(DocumentEvent e) {
				usernameFieldActionPerformed(e);				
			}
			
			@Override
			public void changedUpdate(DocumentEvent e) {
				usernameFieldActionPerformed(e);				
			}
		});

        jLabel1.setText("Username");
        jLabel1.setName("jLabel1"); // NOI18N

        usernameErrorLabel.setFont(new java.awt.Font("Lucida Grande 10", 0, 12)); // NOI18N
        usernameErrorLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        usernameErrorLabel.setText("");
        usernameErrorLabel.setName("usernameErrorLabel"); // NOI18N

        javax.swing.GroupLayout usernamePanelLayout = new javax.swing.GroupLayout(usernamePanel);
        usernamePanel.setLayout(usernamePanelLayout);
        usernamePanelLayout.setHorizontalGroup(
            usernamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(usernamePanelLayout.createSequentialGroup()
                .addGap(10, 10, 10)
                .addGroup(usernamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(instructionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE)
                    .addGroup(usernamePanelLayout.createSequentialGroup()
                        .addGap(90, 90, 90)
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(195, 195, 195))
                    .addGroup(usernamePanelLayout.createSequentialGroup()
                        .addGap(38, 38, 38)
                        .addComponent(usernameErrorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 392, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        usernamePanelLayout.setVerticalGroup(
            usernamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(usernamePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(72, 72, 72)
                .addGroup(usernamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jLabel1)
                    .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(usernameErrorLabel)
                .addContainerGap(78, Short.MAX_VALUE))
        );

        usernamePanel.setBounds(10, 10, 530, 318);
        jLayeredPane1.add(usernamePanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        profilePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Enter Profile Information"));
        profilePanel.setName("profilePanel"); // NOI18N

        instructionLabel1.setText("<html>Next you will need to enter some basic profile information.</html>");
        instructionLabel1.setName("instructionLabel1"); // NOI18N

        realnameField.setName("realnameField"); // NOI18N
        realnameField.getDocument().addDocumentListener(new DocumentListener() {
			
			@Override
			public void removeUpdate(DocumentEvent e) {
				realnameFieldActionPerformed(e);
			}
			
			@Override
			public void insertUpdate(DocumentEvent e) {
				realnameFieldActionPerformed(e);
			}
			
			@Override
			public void changedUpdate(DocumentEvent e) {
				realnameFieldActionPerformed(e);				
			}
		});

        jLabel2.setText("Real Name");
        jLabel2.setName("jLabel2"); // NOI18N

        realnameErrorLabel.setFont(new java.awt.Font("Lucida Grande 10 12", 0, 12)); // NOI18N
        realnameErrorLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        realnameErrorLabel.setText("Not enough characters");
        realnameErrorLabel.setName("realnameErrorLabel"); // NOI18N

        emailAddressErrorLabel.setFont(new java.awt.Font("Lucida Grande 10 12 12", 0, 12)); // NOI18N
        emailAddressErrorLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        emailAddressErrorLabel.setText("Not enough characters");
        emailAddressErrorLabel.setName("emailAddressErrorLabel"); // NOI18N

        emailAddressField.setName("emailAddressField"); // NOI18N
        emailAddressField.getDocument().addDocumentListener(new DocumentListener() {
			
			@Override
			public void removeUpdate(DocumentEvent e) {
				emailAddressFieldActionPerformed(e);
			}
			
			@Override
			public void insertUpdate(DocumentEvent e) {
				emailAddressFieldActionPerformed(e);
			}
			
			@Override
			public void changedUpdate(DocumentEvent e) {
				emailAddressFieldActionPerformed(e);
			}
		});

        jLabel3.setText("Email Address");
        jLabel3.setName("jLabel3"); // NOI18N

        javax.swing.GroupLayout profilePanelLayout = new javax.swing.GroupLayout(profilePanel);
        profilePanel.setLayout(profilePanelLayout);
        profilePanelLayout.setHorizontalGroup(
            profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(profilePanelLayout.createSequentialGroup()
                .addGap(52, 52, 52)
                .addGroup(profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addComponent(jLabel3))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(realnameField, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(emailAddressField, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
            .addGroup(profilePanelLayout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(emailAddressErrorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 392, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(106, Short.MAX_VALUE))
            .addGroup(profilePanelLayout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(instructionLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
            .addGroup(profilePanelLayout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(realnameErrorLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 392, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(106, Short.MAX_VALUE))
        );
        profilePanelLayout.setVerticalGroup(
            profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(profilePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jLabel2)
                    .addComponent(realnameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(realnameErrorLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(profilePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jLabel3)
                    .addComponent(emailAddressField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(emailAddressErrorLabel)
                .addContainerGap(83, Short.MAX_VALUE))
        );

        profilePanel.setBounds(10, 10, 530, 318);
        jLayeredPane1.add(profilePanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Create Encryption Key"));
        keyPanel.setName("keyPanel"); // NOI18N

        instructionLabel2.setText("<html>All data in the cloud is secured with encryption.  This encryption uses a special file called a private key to keep your data safe.<br/><br/>Select a location and name for your private key.  Keep this file safe! If you lose this file, you will no longer be able to access the cloud notebook database.  There is no way to recreate this file if you lose it!<br/><br/>After you've selected the filename for your private key, click next to create the key and transmit your new user information to the cloud.</html>");
        instructionLabel2.setName("instructionLabel2"); // NOI18N

        filenameField.setEditable(false);
        filenameField.setName("filenameField"); // NOI18N

        jLabel5.setText("Private Key File");
        jLabel5.setName("jLabel5"); // NOI18N

        browseButton.setText("Browse");
        browseButton.setName("browseButton"); // NOI18N
        browseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                browseButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout keyPanelLayout = new javax.swing.GroupLayout(keyPanel);
        keyPanel.setLayout(keyPanelLayout);
        keyPanelLayout.setHorizontalGroup(
            keyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(keyPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(keyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, keyPanelLayout.createSequentialGroup()
                        .addComponent(filenameField, javax.swing.GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(browseButton))
                    .addComponent(jLabel5)
                    .addComponent(instructionLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE))
                .addContainerGap())
        );
        keyPanelLayout.setVerticalGroup(
            keyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, keyPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jLabel5)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(keyPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(filenameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(browseButton))
                .addGap(54, 54, 54))
        );

        keyPanel.setBounds(10, 10, 530, 260);
        jLayeredPane1.add(keyPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        errorPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Whoops..."));
        errorPanel.setName("errorPanel"); // NOI18N

        instructionLabel4.setText("<html>Unfortunately an unexpected error occurred and the wizard cannot finish.  Please cancel and try again.</html>");
        instructionLabel4.setName("instructionLabel4"); // NOI18N

        javax.swing.GroupLayout errorPanelLayout = new javax.swing.GroupLayout(errorPanel);
        errorPanel.setLayout(errorPanelLayout);
        errorPanelLayout.setHorizontalGroup(
            errorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, errorPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)
                .addContainerGap())
        );
        errorPanelLayout.setVerticalGroup(
            errorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(errorPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(134, Short.MAX_VALUE))
        );

        errorPanel.setBounds(10, 10, 530, 318);
        jLayeredPane1.add(errorPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        finishPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Created!"));
        finishPanel.setName("finishPanel"); // NOI18N

        instructionLabel3.setText("<html>You're all set to access math notebooks in the cloud.  Keep your key file safe and happy plotting!</html>");
        instructionLabel3.setName("instructionLabel3"); // NOI18N

        javax.swing.GroupLayout finishPanelLayout = new javax.swing.GroupLayout(finishPanel);
        finishPanel.setLayout(finishPanelLayout);
        finishPanelLayout.setHorizontalGroup(
            finishPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, finishPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)
                .addContainerGap())
        );
        finishPanelLayout.setVerticalGroup(
            finishPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(finishPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(instructionLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(134, Short.MAX_VALUE))
        );

        finishPanel.setBounds(10, 10, 530, 318);
        jLayeredPane1.add(finishPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 553, Short.MAX_VALUE)
            .addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 553, Short.MAX_VALUE)
            .addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 392, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 329, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(buttonPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        pack();
    }// </editor-fold>

    private void resetAll() {
    	this.cancelButton.setEnabled(true);
    	this.backButton.setEnabled(false);
    	this.nextButton.setEnabled(false);
    	this.finishButton.setEnabled(false);
    	this.welcomePanel.setVisible(false);
    	this.usernamePanel.setVisible(false);
    	this.profilePanel.setVisible(false);
    	this.keyPanel.setVisible(false);
    	this.finishPanel.setVisible(false);
    	this.errorPanel.setVisible(false);
    }
    private void setWelcomeState() {
    	this.resetAll();
    	this.state = State.WELCOME;
    	this.nextButton.setEnabled(true);
    	this.welcomePanel.setVisible(true);
    	this.progressBar.setValue(0);
    }
    
    private void setUsernameState() {
    	this.resetAll();
    	this.state = State.USERNAME;
    	this.backButton.setEnabled(true);
    	this.usernamePanel.setVisible(true);
    	this.progressBar.setValue(0);
		this.usernameFieldActionPerformed(null);
    }
    
    private void setProfileState() {
    	this.resetAll();
    	this.state = State.PROFILE;
    	this.backButton.setEnabled(true);
    	this.profilePanel.setVisible(true);
    	this.progressBar.setValue(33);
		this.checkRealnameEmailFields();
    }
    
    private void setKeyState() {
    	this.resetAll();
    	this.state = State.KEY;
    	this.backButton.setEnabled(true);
    	this.keyPanel.setVisible(true);
    	this.progressBar.setValue(66);
    	this.nextButton.setEnabled(this.filenameField.getText().length() > 0);
    }
    
    private void setCompleteState() {
    	this.resetAll();
    	this.state = State.COMPLETE;
    	this.finishPanel.setVisible(true);
    	this.finishButton.setEnabled(true);
    	this.cancelButton.setEnabled(false);
    	this.progressBar.setValue(100);


    }
    
    private void setErrorState() {
    	this.resetAll();
    	this.state = State.USERNAME;
    	this.errorPanel.setVisible(true);
    	this.progressBar.setValue(0);

    }
    
    /** Closes the dialog */
    private void closeDialog(java.awt.event.WindowEvent evt) {                             
        doClose(RET_CANCEL);
    }                            

    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {
       doClose(RET_CANCEL);
}

    private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {
        switch(this.state){
        case USERNAME:
        	this.setWelcomeState();
        	break;
        case PROFILE:
        	this.setUsernameState();
        	break;
        case KEY:
        	this.setProfileState();
        	break;
        }
}

    private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {
    	switch(this.state) {
    		case WELCOME:
    			this.setUsernameState();
    			break;
    		case USERNAME:
    			this.setProfileState();
    			break;
    		case PROFILE:
    			this.setKeyState();
    			break;
    		case KEY:
    			this.createUser();
    			break;
    	}
    }

    private void finishButtonActionPerformed(java.awt.event.ActionEvent evt) {
    		doClose(RET_OK);
    }
    
    private void createUser() {
    	boolean success = true;
    	SimpleRSAKeyPair kp = SimpleRSAKeyPair.generateKeyPair();
    	try {
			kp.getPrivate().writeToFile(this.filenameField.getText());
		} catch (IOException e) {
			this.setErrorState();
		}
		
		try {
			DBPerson.createPerson(this.context, this.usernameField.getText().toLowerCase(), this.realnameField.getText(), this.emailAddressField.getText(), kp.getPublic().getEncoded());
		} catch (DatabaseException e) {
			this.setErrorState();
		}
		this.setCompleteState();
    }
    
    private void setFieldErrorMessage(JTextField field, JLabel errorLabel, boolean isError, String message) {
    	errorLabel.setText(message);
    	field.setBackground(isError
    						 ? new Color(1.0f,0.9f,0.9f)
    						 : new Color(0.9f,1.0f,0.9f));
    	if(isError) {
    		this.nextButton.setEnabled(false);
    	}
    }

    private void usernameFieldActionPerformed(DocumentEvent e) {
    	String username = this.usernameField.getText().toLowerCase();
    	
    	this.usernameErrorLabel.setText("");
    	this.usernameField.setBackground(Color.white);
    	this.nextButton.setEnabled(true);
        if(username.length() < 4) {
        	this.nextButton.setEnabled(false);
        	this.usernameErrorLabel.setText("Too short.");
        	this.usernameField.setBackground(new Color(1.0f,0.9f,0.9f));
        } else if(username.length() > 30) {
        	this.nextButton.setEnabled(false);
        	this.usernameErrorLabel.setText("Too long.");
        	this.usernameField.setBackground(new Color(1.0f,0.9f,0.9f));
        } else {
        	this.progressBar.setIndeterminate(true);
        	boolean usernameAvailable = false;
        	
        	try {
				usernameAvailable = DBPerson.isUsernameAvailable(context, username);
			} catch (DatabaseException e1) {}
			
        	if(usernameAvailable) {
        		this.nextButton.setEnabled(true);
        		this.usernameField.setBackground(new Color(0.9f,1.0f,0.9f));
        		this.usernameErrorLabel.setText(String.format("The username %s is available.", username));
        	} else {
        		this.nextButton.setEnabled(false);
        		this.usernameField.setBackground(new Color(1.0f,0.9f,0.9f));
        		this.usernameErrorLabel.setText(String.format("The username %s is taken.", username));
        	}
        	this.progressBar.setIndeterminate(false);
        }
}

    private void checkRealnameEmailFields() {
    	String realname = this.realnameField.getText();
    	String email = this.emailAddressField.getText();
    	boolean error = false;
    	if(realname.length() < 4) {
    		this.setFieldErrorMessage(realnameField, realnameErrorLabel, true, "Too short.");
    		error = true;
    	} else {
    		this.setFieldErrorMessage(realnameField, realnameErrorLabel, false, "OK");
    	}
    	
    	if(email.length() < 4) {
    		this.setFieldErrorMessage(emailAddressField, emailAddressErrorLabel, true, "Too short.");
    		error = true;
    	} else if(!email.matches(".+@.+\\..+")) {
    		this.setFieldErrorMessage(emailAddressField, emailAddressErrorLabel, true, "Not valid email address format");
    		error = true;
    	} else {
    		this.setFieldErrorMessage(emailAddressField, emailAddressErrorLabel, false, "OK");
    	}
    	
    	this.nextButton.setEnabled(!error);
    }
    
    private void realnameFieldActionPerformed(DocumentEvent e) {
    	this.checkRealnameEmailFields();
    }

    private void emailAddressFieldActionPerformed(DocumentEvent e) {
    	this.checkRealnameEmailFields();
    }

    private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {
    
    	JFileChooser chooser = new JFileChooser();
    	//chooser.setAcceptAllFileFilterUsed(false);
    	chooser.setFileFilter(new StringFileFilter("pri", "MathNB Private Keys (*.pri)"));
    	chooser.setMultiSelectionEnabled(false);
    	if(chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
    		String fn = chooser.getSelectedFile().getAbsolutePath();
    		if(!fn.endsWith(".pri")) {
    			fn = fn.concat(".pri");
    		}
    		this.filenameField.setText(fn);
    		this.nextButton.setEnabled(true);
    	}
    }

    private void doClose(int retStatus) {
        returnStatus = retStatus;
        setVisible(false);
        dispose();
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                NewUserWizard dialog = new NewUserWizard(new javax.swing.JFrame(), true, null);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JLabel WelcomeLabel;
    private javax.swing.JButton backButton;
    private javax.swing.JButton browseButton;
    private javax.swing.JPanel buttonPanel;
    private javax.swing.JButton cancelButton;
    private javax.swing.JLabel emailAddressErrorLabel;
    private javax.swing.JTextField emailAddressField;
    private javax.swing.JPanel errorPanel;
    private javax.swing.JTextField filenameField;
    private javax.swing.JButton finishButton;
    private javax.swing.JPanel finishPanel;
    private javax.swing.JLabel instructionLabel;
    private javax.swing.JLabel instructionLabel1;
    private javax.swing.JLabel instructionLabel2;
    private javax.swing.JLabel instructionLabel3;
    private javax.swing.JLabel instructionLabel4;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLayeredPane jLayeredPane1;
    private javax.swing.JPanel keyPanel;
    private javax.swing.JButton nextButton;
    private javax.swing.JPanel profilePanel;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel realnameErrorLabel;
    private javax.swing.JTextField realnameField;
    private javax.swing.JLabel usernameErrorLabel;
    private javax.swing.JTextField usernameField;
    private javax.swing.JPanel usernamePanel;
    private javax.swing.JPanel welcomePanel;
    // End of variables declaration

    private int returnStatus = RET_CANCEL;
}